﻿using UnityEngine;


namespace AmazingAssets
{
    namespace CurvedWorld
    {
        [ExecuteAlways]
        [RequireComponent(typeof(Camera))]
        public class CurvedWorldCamera : MonoBehaviour
        {
            public enum MATRIX_TYPE { Perspective, Orthographic }

            public MATRIX_TYPE matrixType = MATRIX_TYPE.Perspective;
            [Range(1, 179)]
            public float fieldOfView = 60;
            public float size = 5;
            public bool nearClipPlaneSameAsCamera = true;
            public float nearClipPlane = 0.3f;


#if UNITY_EDITOR
            public bool visualizeInEditor;
#endif

            Camera activeCamera;

            private void OnEnable()
            {
                if (activeCamera == null)
                    activeCamera = GetComponent<Camera>();
            }

            private void OnDisable()
            {
                if (activeCamera != null)
                {
                    activeCamera.ResetCullingMatrix();
                }
            }

            private void Start()
            {
                if (activeCamera == null)
                    activeCamera = GetComponent<Camera>();
            }

            private void Update()
            {
                if (activeCamera == null)
                    activeCamera = GetComponent<Camera>();

                if (activeCamera == null)
                {
                    enabled = false;
                    return;
                }


                if (nearClipPlane >= activeCamera.farClipPlane)
                    nearClipPlane = activeCamera.farClipPlane - 0.01f;


                if (matrixType == MATRIX_TYPE.Perspective)
                {
                    fieldOfView = Mathf.Clamp(fieldOfView, 1, 179);
                    activeCamera.cullingMatrix = Matrix4x4.Perspective(fieldOfView, 1, activeCamera.nearClipPlane, activeCamera.farClipPlane) * activeCamera.worldToCameraMatrix;
                }
                else
                {
                    size = size < 1 ? 1 : size;
                    activeCamera.cullingMatrix = Matrix4x4.Ortho(-size, size, -size, size, (nearClipPlaneSameAsCamera ? activeCamera.nearClipPlane : nearClipPlane), activeCamera.farClipPlane) * activeCamera.worldToCameraMatrix;
                }
            }

            private void Reset()
            {
                if (activeCamera != null)
                {
                    activeCamera.ResetCullingMatrix();

                    fieldOfView = activeCamera.fieldOfView;
                    size = activeCamera.orthographicSize;
                    nearClipPlane = activeCamera.nearClipPlane;
                }
            }
#if UNITY_EDITOR
            private void OnDrawGizmos()
            {
                if (activeCamera == null || visualizeInEditor == false)
                    return;


                Gizmos.color = Color.magenta * 0.85f;

                if (matrixType == MATRIX_TYPE.Perspective)
                {
                    Gizmos.matrix = transform.localToWorldMatrix;
                    Gizmos.DrawFrustum(Vector3.zero, fieldOfView, activeCamera.farClipPlane, activeCamera.nearClipPlane, 1);
                }
                else
                {
                    //Top
                    Vector3 c = transform.position + transform.forward * (nearClipPlaneSameAsCamera ? activeCamera.nearClipPlane : nearClipPlane);

                    Vector3 t1 = c + transform.up * size - transform.right * size;
                    Vector3 t2 = c + transform.up * size + transform.right * size;
                    Vector3 t3 = c - transform.up * size - transform.right * size;
                    Vector3 t4 = c - transform.up * size + transform.right * size;

                    Gizmos.DrawLine(t1, t2);
                    Gizmos.DrawLine(t2, t4);
                    Gizmos.DrawLine(t3, t4);
                    Gizmos.DrawLine(t3, t1);


                    //Bottom
                    c = transform.position + transform.forward * activeCamera.farClipPlane;

                    Vector3 b1 = c + transform.up * size - transform.right * size;
                    Vector3 b2 = c + transform.up * size + transform.right * size;
                    Vector3 b3 = c - transform.up * size - transform.right * size;
                    Vector3 b4 = c - transform.up * size + transform.right * size;

                    Gizmos.DrawLine(b1, b2);
                    Gizmos.DrawLine(b2, b4);
                    Gizmos.DrawLine(b3, b4);
                    Gizmos.DrawLine(b3, b1);


                    //Connection
                    Gizmos.DrawLine(t1, b1);
                    Gizmos.DrawLine(t2, b2);
                    Gizmos.DrawLine(t3, b3);
                    Gizmos.DrawLine(t4, b4);
                }
            }
#endif
        }
    }
}